import IEntity from "../Interfaces/IEntity";
import MonsterAssetStruct from "../Structs/MonsterAssetStruct";
import INavigate from "../Interfaces/INavigate";
import Oriented from "../Constants/Oriented";
import PasteWall from "../Components/Navigate/PasteWall";
import C from "../Configs/Config";
import EntityTypes from "../Constants/EntityTypes";
import Patrol from "../Components/Navigate/Patrol";
import G from "../Utilities/Global";
import Constants from "../Constants/Constants";
import PatrolStraight from "../Components/Navigate/PatrolStraight";
import FsMachine from "../Lib/StateMachine/Fsmachine";
import AnimationController from "../Controllers/AnimationController";
import eState from "../Lib/StateMachine/eState";
import StateEvent from "../Lib/StateMachine/StateEvent";
import MonsterBehaviour from "../Constants/MonsterBehaviour";
import Bullet from "./Bullet";
import EntityGroup from "../Constants/EntityGroup";
import PatrolVert from "../Components/Navigate/PatrolVert";

/**
 * 怪物
 * created by Five on 2018-11-19 15:42:58
 */
const { ccclass, property } = cc._decorator

@ccclass
export default class Monster extends cc.Component implements IEntity {
    Group: EntityGroup = EntityGroup.MONSTER;
    Data: MonsterAssetStruct;

    // 动画节点
    AnimNode: cc.Node = null;
    // 碰撞组件
    RigidBody: cc.RigidBody = null;
    // 寻路
    _navigater: INavigate;
    // 状态机
    Fsm: FsMachine = null;
    // 时间静止
    Pause: boolean = false;
    // 动画加载完成
    private _initFinish: boolean = false;

    // 生存时间
    private _last: number = Number.POSITIVE_INFINITY;

    // 攻击间隔
    private _attack_span: number = 0;

    // 跳跃间隔
    private _jump_span: number = 0;

    public _oriented(): Oriented {
        if (this._navigater == null)
            return this.Data.oriented;
        return this._navigater.oriented;
    }

    public SetData(d: MonsterAssetStruct) {
        this.Data = d;
        if (this.Data.last > 0)
            this._last = this.Data.last;
        this.RigidBody = this.getComponent(cc.RigidBody);
        // if (!C().BehaviorLike(this.Data, MonsterBehaviour.FLYABLE))
        // this.RigidBody.type = cc.RigidBodyType.Dynamic;
    }

    public async SetAnim(node: cc.Node) {
        this.AnimNode = node;
        let anim = new AnimationController(this.AnimNode, this.Data.asset);
        await anim.initClips();
        this._initFinish = true;
        this.Fsm = new FsMachine(anim);
    }

    // 初始化移动回调,初始朝向等
    public Init() {
        this.schedule(() => {
            if (this._navigater == null)
                return;
            this._navigater.settarget(this.node);
        }, 0.5);
        this.AnimNode.is3DNode = true;
        this.AnimNode.eulerAngles = this.Data.oriented == Oriented.RIGHT ? Constants.OppsiteRotate : cc.Vec3.ZERO;
    }

    public SetNav() {
        if (C().BehaviorLike(this.Data, MonsterBehaviour.PATROL)) {
            this._navigater = new Patrol();
        }
        else if (C().BehaviorLike(this.Data, MonsterBehaviour.PASTEWALL)) {
            this._navigater = new PasteWall();
        }
        else if (C().BehaviorLike(this.Data, MonsterBehaviour.PATROLSTRAIGHT)) {
            this._navigater = new PatrolStraight();
        }
        else if (C().BehaviorLike(this.Data, MonsterBehaviour.PATROLVERTICAL)) {
            this._navigater = new PatrolVert();
        }
        else {
            // 没有配置移动方式的,视为静止
            return;
        }
        // this.Data.oriented = G().TestOri ? Oriented.RIGHT : Oriented.LEFT;       
        this.AnimNode.is3DNode = true;
        this.AnimNode.eulerAngles = this.Data.oriented == Oriented.RIGHT ? Constants.OppsiteRotate : cc.Vec3.ZERO;
        // G().TestOri = !G().TestOri;
        this._navigater.setdir(this.Data.oriented);
        this._navigater.setspeed(this.Data.speed);
        this._navigater.setsize(Constants.ENTITY_EDGE);
    }

    private falling: boolean = false;
    update(dt: number) {
        if (this.Pause)
            return;

        if (!this._initFinish)
            return;

        // 下面是寻路的部分
        this.navigate(dt);
        // 下面是其他的行为
        this.behaviour(dt);
    }

    behaviour(dt: number) {
        // 下落中就不搞你了
        if (this.falling) {
            return;
        }
        // 如果是会攻击的怪
        if (C().BehaviorLike(this.Data, MonsterBehaviour.ATTACK)) {
            if (this._attack_span >= this.Data.bespan) {
                this._attack_span = 0;
                let state = new StateEvent(null, () => {
                    this.shot();
                    this.Fsm.Quit();
                })
                this.Fsm.ChangeState(eState.ATTACK, state);
            }
            this._attack_span += dt;
        }
    }

    async shot() {
        let bullet = await G().Res.GetRes(Constants.PRE_BULLET) as cc.Node;
        let pos = this.node.position;
        let oriented = this.Data.oriented;
        if (this._navigater != null)
            oriented = this._oriented();
        // 子父关系节点
        let edge = Constants.ENTITY_EDGE;
        pos.x += oriented == Oriented.RIGHT ? edge / 2 : -edge / 2;
        bullet.position = pos;
        bullet.addComponent(Bullet).SetDir(oriented);
        bullet.getComponent(Bullet).SetNavigater();
        bullet.getComponent(Bullet).SetOwner(this);
        bullet.getComponent(Bullet).SetLifeTime(20);
        this.node.parent.addChild(bullet);
    }

    navigate(dt: number) {
        if (this.Data && !this.falling && !C().BehaviorLike(this.Data, MonsterBehaviour.FLYABLE)) {
            let ori = this._oriented();
            let pos = this.node.position;
            let dpos = G().Calc.DO(pos, ori);
            let loc = G().Calc.PositionToLocation(pos);
            let dloc = G().Calc.PositionToLocation(dpos);
            let entityTarDown = G().CurScene.MapData.GetWallByPosition(dpos);
            if (!entityTarDown) {
                this.falling = true;
                cc.log(loc + " " + dloc);
            }
        }

        if (this.falling) {
            this.Falling(dt);
            return;
        }

        if (this._last <= 0) {
            this.die();
            return;
        }

        if (this._navigater == null)
            return;

        this._last -= dt;
        this._navigater.update(dt, this.node, this.AnimNode);
        this.Fsm.ChangeState(eState.MOVE);
        if (this.Fsm != null)
            this.Fsm.Tick();
    }

    Falling(dt: number) {
        let position = this.node.position;

        // 掉落死亡的怪会翻转
        if (C().BehaviorLike(this.Data, MonsterBehaviour.DROPDEAD))
            this.AnimNode.rotationX = 180;

        let pos = this.node.position;
        let entity = G().CurScene.MapData.GetWallByPosition(G().Calc.DC(pos, this._oriented()));
        // 要么掉下来摔死,要么掉下来继续跑
        if (entity && C().BehaviorLike(this.Data, MonsterBehaviour.DROPDEAD)) {
            this.die();
        } else if (entity && C().IsTypeOf(entity.Asset, EntityTypes.COLLISION)) {
            // TODO 考虑向玩家冲刺吧小伙子
            this.falling = false;
        }
        position.subSelf(cc.v2(0, Constants.Gravity * dt));
        this.node.position = position;
    }

    private jump() {

    }

    public Freeze() {
        this.Pause = true;
        this.Fsm.animNode.pause();
    }

    public UnFreeze() {
        this.Pause = false;
        this.Fsm.animNode.resume();
    }

    /**
     * 受击
     * @param who 
     */
    public Hitted(who: IEntity) {
        // 目前的打到就死了
        this.die();
    }

    die() {
        // 可能会有爆炸什么的事件,暂时只有掉落
        this.falling = false;
        this._navigater = null;
        let seq = cc.sequence(cc.fadeOut(0.1), cc.fadeIn(0.1));
        this.node.runAction(cc.sequence(seq, seq, seq, cc.callFunc(() => {
            this.dropdown();
            this.node.removeFromParent();
            this.node.destroy();
        })))
    }

    async explosion() {
        let clip = await G().Res.LoadFile("clips", "")
    }

    dropdown() {
        cc.log("TODO monster dropdown ", this.Data.dropdown);
    }
}